package com.hibase.core.rule.service.ruletable.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hibase.common.entity.PageBase;
import com.hibase.core.rule.constant.RuleFieldType;
import com.hibase.core.rule.entity.ruletable.RuleTable;
import com.hibase.core.rule.entity.ruletable.RuleTableData;
import com.hibase.core.rule.entity.ruletable.RuleTableField;
import com.hibase.core.rule.entity.ruletable.query.RuleQueryResultVO;
import com.hibase.core.rule.entity.ruletable.query.RuleTableDataChangeVO;
import com.hibase.core.rule.entity.ruletable.query.TableQuerySearchVO;
import com.hibase.core.rule.entity.ruletableversion.RuleTableVersion;
import com.hibase.core.rule.service.ruletable.RuleTableDataService;
import com.hibase.core.rule.service.ruletable.RuleTableFieldService;
import com.hibase.core.rule.service.ruletable.RuleTableQueryService;
import com.hibase.core.rule.service.ruletable.RuleTableService;
import com.hibase.core.rule.service.ruletableversion.RuleTableVersionService;
import com.hibase.core.rule.utils.RuleUtils;
import com.hibase.core.web.entity.OperationIdsEntity;
import com.hibase.common.exception.HibaseAssert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 描述:
 *
 * @author li-wei-hua
 * @date 2020-04-08 15:24
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class RuleTableQueryServiceImpl implements RuleTableQueryService {

    @Autowired
    private RuleTableService ruleTableService;

    @Autowired
    private RuleTableDataService ruleTableDataService;

    @Autowired
    private RuleTableFieldService ruleTableFieldService;

    @Autowired
    private RuleTableVersionService ruleTableVersionService;

    @Override
    public RuleQueryResultVO selectTableData(TableQuerySearchVO searchVO) {

        // step 1. 获取要查询的表
        RuleTableVersion tableVersion = ruleTableVersionService.getById(searchVO.getRuleTableVersionId());
        HibaseAssert.notNull(tableVersion,"查询动态表失败");
        RuleTable ruleTable = ruleTableService.getById(tableVersion.getRuleTableId());
        HibaseAssert.notNull(ruleTable,"未找到动态表 : ");

        // step 2. 获取所有表中所有列 按列顺序排序
        List<RuleTableField> ruleTableFieldList = ruleTableFieldService.list(new QueryWrapper<RuleTableField>().eq("rule_table_id", ruleTable.getId()).orderByAsc("column_sort"));
        // 获取查询项字段Map
        Map<String, RuleTableField> queryFieldMap = ruleTableFieldList.stream().filter(p->p.getFiledType().equals(RuleFieldType.QUERY.getKey())).collect(Collectors.toMap(RuleTableField::getFieldName, Function.identity()));

        // step 3. 解析查询项
        QueryWrapper<RuleTableData> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("rule_table_version_id",searchVO.getRuleTableVersionId());

        Optional.ofNullable(searchVO.getQueryMap()).ifPresent(p->{
            // 判断字段是否为查询属性
            p.forEach((k,v)->{
                HibaseAssert.isTrue(queryFieldMap.get(k)!=null,"未知的查找项 : ".concat(k));
            });

            // 通过  json_extract  设置查询json类型数据
            Map<String, String> queryJsonMap = p.entrySet().stream().collect(Collectors.toMap(k -> "eav_find_data -> '$.".concat("\"").concat(k.getKey()).concat("\"'"), Map.Entry::getValue));
            queryWrapper.allEq(queryJsonMap,false);
        });

        // step 4. 排序设置
        if (StrUtil.isNotBlank(searchVO.getSortField())&&StrUtil.isNotBlank(searchVO.getSortModel())){
            queryWrapper.orderBy(true,"asc".equals(searchVO.getSortModel()),"eav_value_data -> '$.".concat(searchVO.getSortField()).concat("'"));
        }
        queryWrapper.orderByAsc("row_sort");

        // step 5. 获取查询结果
        PageInfo<RuleTableData> page = ruleTableDataService.page(searchVO, queryWrapper);

        // step 6. 数据处理
        List<JSONObject> dataList = new LinkedList<>();
        for (RuleTableData p : page.getList()) {
            JSONObject jsonFindObject = JSON.parseObject(p.getEavFindData());
            JSONObject jsonValueObject = JSON.parseObject(p.getEavValueData());
            JSONObject jsonObject = new JSONObject();
            jsonObject.putAll(jsonFindObject);
            jsonObject.putAll(jsonValueObject);
            jsonObject.put("id", p.getId());
            jsonObject.put("columnSort", p.getRowSort());
            dataList.add(jsonObject);
        }
//        List<JSONObject> dataList = page.getList().stream().map(p -> {
//            JSONObject jsonFindObject = JSON.parseObject(p.getEavFindData());
//            JSONObject jsonValueObject = JSON.parseObject(p.getEavValueData());
//            JSONObject jsonObject = new JSONObject();
//            jsonObject.putAll(jsonFindObject);
//            jsonObject.putAll(jsonValueObject);
//            jsonObject.put("id", p.getId());
//            jsonObject.put("columnSort", p.getColumnSort());
//            return jsonObject;
//        }).collect(Collectors.toList());

        PageInfo pageInfo = new PageInfo(page.getList());
        pageInfo.setList(dataList);

        // step 7. 获取表头信息
        List<String> fieldList = ruleTableFieldList.stream().map(RuleTableField::getFieldName).collect(Collectors.toList());

        // step 8. 组装返回对象
        RuleQueryResultVO result = new RuleQueryResultVO();
        result.setDataPage(pageInfo);
        //result.setFieldList(fieldList);
        result.setFieldList(ruleTableFieldList);
        result.setQueryItem(queryFieldMap.keySet());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeData(RuleTableDataChangeVO insertVO) {
        RuleTableData entity = new RuleTableData();

        RuleTableVersion ruleTableVersion = ruleTableVersionService.getById(insertVO.getRuleTableVersionId());
        HibaseAssert.notNull(ruleTableVersion,"未找到版本表");

        // step 1. 获取要查询的表
        RuleTable ruleTable = ruleTableService.getById(ruleTableVersion.getRuleTableId());

        HibaseAssert.notNull(ruleTable,"未找到动态表");


        // step 2. 获取所有表中所有列
        List<RuleTableField> ruleTableFieldList = ruleTableFieldService.list(new QueryWrapper<RuleTableField>().eq("rule_table_id", ruleTable.getId()).orderByAsc("column_sort"));
        Map<String, RuleTableField> fieldMap = new LinkedHashMap<>();
        for (RuleTableField ruleTableField : ruleTableFieldList) {
            fieldMap.put(ruleTableField.getFieldName(), ruleTableField);
        }
        //Map<String, RuleTableField> fieldMap = ruleTableFieldList.stream().collect(Collectors.toMap(RuleTableField::getFieldName, Function.identity()));

        // step 3. 字段的非空校验
        List<RuleTableData> dataList = Lists.newArrayList();
        //key:字段名，value：字段的值
        Map<String, String> data = insertVO.getDataList();
        if (StrUtil.isNotBlank(insertVO.getId())) {
            entity.setId(insertVO.getId());
        }
        Map<String,String> findData = new LinkedHashMap<>();
        Map<String,String> valueData = new LinkedHashMap<>();
        Map<String,String> valueDataTemp = new LinkedHashMap<>();



        for (Map.Entry<String, String > dataEntity : data.entrySet()){
            for (Map.Entry<String , RuleTableField> fieldEntry : fieldMap.entrySet()){

                if ((dataEntity.getKey().equals(fieldEntry.getKey()) || dataEntity.getKey().equals(fieldEntry.getValue().getFieldAliasName())) && fieldEntry.getValue().getFiledType().equals(RuleFieldType.QUERY.getKey())){
                    //查找项添加到findData中
                    //匹配字段名==数据库中的字段名，或者 字段名==数据库中字段的别名
                    findData.put(dataEntity.getKey(),dataEntity.getValue());
                    break;
                }else if ((dataEntity.getKey().equals(fieldEntry.getKey()) || dataEntity.getKey().equals(fieldEntry.getValue().getFieldAliasName())) && fieldEntry.getValue().getFiledType().equals(RuleFieldType.RANGE_QUERY.getKey())){
                    //范围查找项添加到valueData中
                    valueData.put(fieldEntry.getKey(),dataEntity.getValue());
                    if (RuleFieldType.RANGE_LEFT_FIELD.getKey().equals(dataEntity.getKey()) || dataEntity.getKey().equals(fieldEntry.getValue().getFieldAliasName())){
                        entity.setEavRangeStartVal(new BigDecimal(dataEntity.getValue()));
                    }
                    if (RuleFieldType.RANGE_RIGHT_FIELD.getKey().equals(dataEntity.getKey()) || dataEntity.getKey().equals(fieldEntry.getValue().getFieldAliasName())){
                        entity.setEavRangeEndVal(new BigDecimal(dataEntity.getValue()));
                    }
                    break;
                } else if ((dataEntity.getKey().equals(fieldEntry.getKey()) || dataEntity.getKey().equals(fieldEntry.getValue().getFieldAliasName())) && fieldEntry.getValue().getFiledType().equals(RuleFieldType.VALUE.getKey())){
                    //添加值项
                    // 匹配字段名==数据库中的字段名，或者 字段名==数据库中字段的别名
                    valueDataTemp.put(fieldEntry.getKey(),dataEntity.getValue());
                    if (RuleFieldType.PRIORITY_FIELD.getKey().equals(dataEntity.getKey())){
                        entity.setEavPriority(Integer.valueOf(dataEntity.getValue()));
                    }
                    break;
                }
            }
        }
        valueData.putAll(valueDataTemp);
        //todo 允许为空的字段
        Map<String, Boolean> isEmptyFieldMap = ruleTableFieldList.stream().filter(RuleTableField::getBeEmpty).collect(Collectors.toMap(RuleTableField::getFieldName, RuleTableField::getBeEmpty));
        //

        //校验重复数据，适用于 一对一场景


        QueryWrapper<RuleTableData> wrapper = new QueryWrapper<>();
        //wrapper.select("max(column_sort) AS column_sort");
        wrapper.eq("rule_table_version_id",insertVO.getRuleTableVersionId());
        wrapper.orderByDesc("row_sort").last( "limit 1");
        RuleTableData lastData = ruleTableDataService.getOne(wrapper);
        //没有数据则行号为1
        if (lastData == null){
            entity.setRowSort((BigDecimal.ONE));
        }else {
            entity.setRowSort(lastData.getRowSort().add(BigDecimal.ONE));
        }
        entity.setRuleTableVersionId(insertVO.getRuleTableVersionId());
        entity.setEavFindData(JSON.toJSONString(findData));
        entity.setEavValueData(JSON.toJSONString(valueData));

        entity.setEavFindHash(RuleUtils.getHash(ruleTable.getName(),ruleTableVersion.getName(), JSON.toJSONString(findData)));
        ruleTableDataService.store(entity);

//        data.forEach(k, v->{
//            // 判断数据和字段是否完全匹配
//            ArrayList<String> dataKey = new ArrayList<>(p.keySet());
//            dataKey.remove("id");
//            ArrayList<String> fieldKey = new ArrayList<>(fieldMap.keySet());
//            dataKey.sort(Comparator.comparing(String::hashCode));
//            fieldKey.sort(Comparator.comparing(String::hashCode));
//            HibaseAssert.isTrue(dataKey.toString().equals(fieldKey.toString()),"数据字段和表字段不匹配");
//            // todo 非空字段校验
//
//            // 添加到数据集
//            RuleTableData ruleTableData = new RuleTableData();
//            ruleTableData.setId((String) p.get("id"));
//            ruleTableData.setRuleTableId(ruleTable.getId());
//            ruleTableData.setRuleTableVersionId(insertVO.getRuleTableVersionId());
//            ruleTableData.setEavData(JSON.toJSONString(p));
//
//            // todo 查询项多值唯一校验
//
//            dataList.add(ruleTableData);
//        });
//
//        // step 4. 数据处理
//        ruleTableDataService.storeBatch(dataList);
        log.info("【动态表数据】 表: {} | 新增数据 : {} | \n {}",ruleTable.getName(),dataList.size(),dataList.toString());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateData(Map<String,Object> updateVO) {

        String id = (String) updateVO.get("id");
        HibaseAssert.isTrue(id!=null,"id不能为空");

        // step 1. 获取表信息
        RuleTableData ruleTableData = ruleTableDataService.getById(id);

        HibaseAssert.notNull(ruleTableData,"未查询到记录");

        RuleTableVersion ruleTableVersion = ruleTableVersionService.getById(ruleTableData.getRuleTableVersionId());

        updateVO.remove("id");

        // step 2. 获取所有表中所有列
        List<RuleTableField> ruleTableFieldList = ruleTableFieldService.list(new QueryWrapper<RuleTableField>().eq("rule_table_id", ruleTableVersion.getRuleTableId()).orderByAsc("column_sort"));
        Map<String, RuleTableField> fieldMap = ruleTableFieldList.stream().collect(Collectors.toMap(RuleTableField::getFieldName, Function.identity()));

        // step 3. 判断数据和字段是否完全匹配
        ArrayList<String> dataKey = new ArrayList<>(updateVO.keySet());
        ArrayList<String> fieldKey = new ArrayList<>(fieldMap.keySet());
        dataKey.sort(Comparator.comparing(String::hashCode));
        fieldKey.sort(Comparator.comparing(String::hashCode));
        HibaseAssert.isTrue(dataKey.toString().equals(fieldKey.toString()),"数据字段和表字段不匹配");

        // step 4. 添加到数据集
        ruleTableData.setEavValueData(JSON.toJSONString(updateVO));

        // step 5. 数据处理
        ruleTableDataService.store(ruleTableData);
        log.info("【动态表修改数据】  {} ",ruleTableData);

    }

    @Override
    public List<JSONObject> matchingData(String tableName) {

        // 查询项
        Map<String,String> queryMap = Maps.newConcurrentMap();

        // step 1. 检查表结构
        // step 1. 获取要查询的表
        RuleTable ruleTable = ruleTableService.getOne(new QueryWrapper<RuleTable>().eq("name", tableName));
        HibaseAssert.notNull(ruleTable,"未找到动态表 : ".concat(tableName));

        // step 2. 获取所有表中所有列
        // step 2. 获取所有表中所有列 按列顺序排序
        List<RuleTableField> ruleTableFieldList = ruleTableFieldService.list(new QueryWrapper<RuleTableField>().eq("rule_table_id", ruleTable.getId()).orderByAsc("column_sort"));
        // 获取查询项字段Map
        Map<String, RuleTableField> queryFieldMap = ruleTableFieldList.stream().filter(p->p.getFiledType().equals(RuleFieldType.QUERY.getKey())).collect(Collectors.toMap(RuleTableField::getFieldName, Function.identity()));

        // step 3. 解析查询项
        QueryWrapper<RuleTableData> queryWrapper = new QueryWrapper<>();
        Optional.ofNullable(queryMap).ifPresent(p->{
            // 判断字段是否为查询属性
            p.forEach((k,v)->{
                HibaseAssert.isTrue(queryFieldMap.get(k)!=null,"未知的查找项 : ".concat(k));
            });

            // 通过  json_extract  设置查询json类型数据
            Map<String, String> queryJsonMap = p.entrySet().stream().collect(Collectors.toMap(k -> "eav_data -> '$.".concat(k.getKey()).concat("'"), Map.Entry::getValue));
            queryWrapper.allEq(queryJsonMap,false);
        });

        // step 4. 排序设置
//        if (StringUtils.isNotBlank(searchVO.getSortField())&&StringUtils.isNotBlank(searchVO.getSortModel())){
//            queryWrapper.orderBy(true,"asc".equals(searchVO.getSortModel()),"eav_data -> '$.".concat(searchVO.getSortField()).concat("'"));
//        }

        // step 5. 获取查询结果
        // todo 测试
        PageBase pageBase = new PageBase();
        pageBase.setCurrentPage(1);
        pageBase.setPageSize(1);
        PageInfo<RuleTableData> page = ruleTableDataService.page(pageBase, queryWrapper);

        // step 6. 数据处理
        List<JSONObject> dataList = page.getList().stream().map(p -> {
            JSONObject jsonObject = JSON.parseObject(p.getEavValueData());
            jsonObject.put("id", p.getId());
            return jsonObject;
        }).collect(Collectors.toList());

        return dataList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteData(OperationIdsEntity idsEntity) {
        ruleTableDataService.deleteBy(idsEntity.getIds());
    }
}
